# Ultralytics YOLO 🚀, AGPL-3.0 license
"""Activation modules."""

import torch
import torch.nn as nn


class AGLU__no_suggest(nn.Module):
    """
    Unified activation function module from https://github.com/kostas1515/AGLU.  
    AGLU（Adaptive Generalized Logistic Unit）是一种自适应激活函数，通过可学习的参数动态调整激活曲线的形状，增强模型对不同数据分布的适应性。
    
    
    """


    def __init__(self, device=None, dtype=None) -> None:
        """Initialize the Unified activation function."""
        super().__init__()
        self.act = nn.Softplus(beta=-1.0)
        # Softplus 函数： Softplus(x) = (1/beta)*log(1 + exp(beta*x) )
        # beta = 1时，Softplus(x)=log(1+exp(x)) 平滑近似 ReLu函数。
        # 在x趋于负无穷，值接近0，x区域正无穷，值区域正无穷，此时 输出约等于输入

        # beta = -1时，表示反向Softplus函数，Softplus(x)=-log(1+exp(-x)) = log( 1/( 1+exp(-x) ) ) = log(sigmoid(x))
        # 在x趋于正无穷，值接近0，x区域负无穷，值区域负无穷，此时 输出约等于输入
        # 这里只用了 beta = -1 的情况。

        # nn.Parameter：将张量标记为可训练参数，自动加入模型的参数列表。
        # nn.init.uniform_：使用均匀分布初始化参数，范围默认为 [0, 1)。
        # torch.empty(1, device=device, dtype=dtype) 创建一个大小为 1 的零维张量（标量）。并指定存储设备与数据类型
        self.lambd = nn.Parameter(nn.init.uniform_(torch.empty(1, device=device, dtype=dtype)))  # lambda parameter
        self.kappa = nn.Parameter(nn.init.uniform_(torch.empty(1, device=device, dtype=dtype)))  # kappa parameter

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        """Compute the forward pass of the Unified activation function."""
        
        #torch.clamp 是 PyTorch 中用于限制张量元素值范围的函数，
        # 通过设定上下界来避免数值过大或过小： clamp(x)=max(min,min(x,max))
        # 常用于防止梯度爆炸、保证数值稳定性或实现特定约束。
        lam = torch.clamp(self.lambd, min=0.0001)  

        """
AGLU(x) = exp( (1/lam) * log( 1/(1+exp( -(k*x-log(lam)) ) ) )
                                        -----------------
                                -----------------------------      
化简为：AGLU(x) = ( 1+e^(-k*x+log(lam)) )^(-1/lam)    

通过调整参数，AGLU 可近似多种激活函数：
小lam使函数在正输入区域快速增长，大lam 使函数更平滑.
kappa（斜率控制）：
大kappa增强非线性，使函数在零点附近更陡峭，小kappa使函数更平缓。


>>>  建议：直接用sigmoid 函数。
        """


        return torch.exp((1 / lam) * self.act((self.kappa * x) - torch.log(lam)))
    


